/**
 * 通用树形结果
 */
export interface TreeResult<TResult> {
  /**
   * 递归形成的树
   */
  tree: TResult[]
  /**
   * 递归时形成的map
   */
  map: Map<any, TResult>
}

/**
 * 通用生成树方法
 * @param source 所有的数据源，用于递归 pnode：父节点当前值
 * @param parentPred 筛选第一级父节点的方法 pnode：已经通过convertFunc转换成为目标类型的父节点 cnode：还未转变的子节点
 * @param childrenPred 筛选子节点的方法
 * @param getChildrenFunc 获取子节点属性的方法 resultNode：已经通过convertFunc转换成为目标类型的父节点
 * @param convertFunc 模型转换方法 有类型T转为TResult
 * @param getMapKeyFunc 获取生成map危机key的方法
 * @returns
 */
export function generateTree<T, TResult>(
  source: T[],
  parentPred: (pnode: T) => boolean,
  childrenPred: (pnode: TResult, cnode: T) => boolean,
  getChildrenFunc: (resultNode: TResult) => TResult[] | undefined,
  convertFunc: (node: T) => TResult,
  getMapKeyFunc?: (resultNode: TResult) => any
): TreeResult<TResult> {
  const result = [] as TResult[]
  const map = new Map<any, TResult>()
  source.filter(parentPred).forEach((t) => {
    const r = convertFunc(t)
    generateSubTree(source, r, childrenPred, getChildrenFunc, convertFunc, map, getMapKeyFunc)
    const key = getMapKeyFunc?.(r)
    if (key != null && key != undefined) {
      map.set(key, r)
    }
    result.push(r)
  })
  return { tree: result, map: map }
}

function generateSubTree<T, TResult>(
  source: T[],
  pnode: TResult,
  childrenPred: (pnode: TResult, cnode: T) => boolean,
  getChildrenFunc: (resultNode: TResult) => TResult[] | undefined,
  convertFunc: (node: T) => TResult,
  map: Map<any, TResult>,
  getMapKeyFunc?: (resultNode: TResult) => any
): void {
  source
    .filter((t) => childrenPred(pnode, t))
    .forEach((t) => {
      const r = convertFunc(t)
      generateSubTree(source, r, childrenPred, getChildrenFunc, convertFunc, map, getMapKeyFunc)
      const children = getChildrenFunc(pnode)
      const key = getMapKeyFunc?.(r)
      if (key != null && key != undefined) {
        map.set(key, r)
      }
      children?.push(r)
    })
}
